/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package astroLib;
/**
 *
 * @author mgeden
 */
public class TimeForSunAngle {
     private RiseSetStatus riseSetStatus;
     private double Cphi,Sphi;
     private double  MJD0;
     private double lambda; // Longitude  Boylam degeri
     public  TimeForSunAngle (double angle, double MJD0h, double lambda, double phi) {
     this.MJD0=  MJD0h;
     this.lambda=lambda;
     double sinh0=Math.sin(Math.toRadians(angle));
     riseSetStatus=new RiseSetStatus();
     Cphi =Math.cos(phi);
     Sphi =Math.sin(phi);
     double hour = 1.0;
     double y_minus, y_0, y_plus;
     double xe, ye, root1, root2;
     int nRoot;
     // Initialize for search
     y_minus = SinAlt(hour-1.0)-sinh0;
     riseSetStatus.above = (y_minus>0.0);
     riseSetStatus.rises = false;
     riseSetStatus.sets  = false;
     // loop over search intervals from [0h-2h] to [22h-24h]
     do {
         y_0    = SinAlt(hour)-sinh0;
         y_plus = SinAlt(hour+1.0)-sinh0;
         // find parabola through three values y_minus,y_0,y_plus
         double[] quadOut=APC_Math.Quad (y_minus,y_0,y_plus);
         xe=quadOut[0]; ye=quadOut[1]; root1=quadOut[2]; root2=quadOut[3];
         nRoot= (int)quadOut[4];
        if ( nRoot==1 ) {
          if ( y_minus < 0.0 )
            { riseSetStatus.LT_Rise = hour+root1;  riseSetStatus.rises = true; }
          else
            { riseSetStatus.LT_Set  = hour+root1;  riseSetStatus.sets  = true; }
        }
         if ( nRoot == 2 ) {
              if ( ye < 0.0 )
               { riseSetStatus.LT_Rise = hour+root2;  riseSetStatus.LT_Set = hour+root1; }
             else
               { riseSetStatus.LT_Rise = hour+root1;  riseSetStatus.LT_Set = hour+root2; }
             riseSetStatus.rises = true; riseSetStatus.sets = true;
         }
         y_minus = y_plus;     // prepare for next interval
         hour += 2.0;

      }
      while ( !( ( hour == 25.0 ) || ( riseSetStatus.rises && riseSetStatus.sets ) ) );

}
     //------------------------------------------------------------------------------
        //
        // SinAlt: Sine of the altitude of Sun or Moon
        //
        // Input:
        //
        //   Hour      Hour
        //
        // <return>:   Sine of the altitude of Sun or Moon at instant of Event
       //------------------------------------------------------------------------------
     private double SinAlt (double Hour)
        {
          //
          // Variables
          //
          double  MJD, T, tau;

          Equatorial sunPosition;

          MJD = MJD0+ Hour/24.0;
          T   = (MJD-51544.5)/36525.0;

          sunPosition=APC_Sun.MiniSun(T);

          tau = APC_Time.GMST(MJD) + lambda - sunPosition.RA;

          return ( Sphi*Math.sin(sunPosition.Dec)+Cphi*Math.cos(sunPosition.Dec)*Math.cos(tau));

        }
        public double getRiseTime ()
        {
            return riseSetStatus.LT_Rise;
        }
        public double getSetTime ()
        {
            return riseSetStatus.LT_Set;
        }
         public boolean isAbove ()
        {
            return riseSetStatus.above;
        }

         public boolean isRises ()
        {
            return riseSetStatus.rises;
        }
        public boolean isSets ()
        {
            return riseSetStatus.sets;
        }
    /**
	 * Compute the sine of the altitude of the object for this date, hour,
	 * and location.
	 * @param	hour		Hour past midnight (for the current MJD)
	 * @result	The sine of the object's altitude above the horizon.
	 *
	 * Note: this overrides Sun.sinAltitude and contains the moon orbital
	 * computation.
	 */
    public double getSinAltitudeForMidday()
    {
        return SinAlt((riseSetStatus.LT_Rise+riseSetStatus.LT_Set)/2);
    }
}